// CRTP (奇异递归模板模式) 详解
// CRTP (Curiously Recurring Template Pattern，奇异递归模板模式) 是C++中一种强大的设计模式，
// 它利用了C++模板和静态多态性的特点，允许在编译时实现多态行为，避免了运行时虚函数调用的开销。

// 基本结构
// CRTP的基本结构如下：
// 基类模板
template <typename Derived>
class Base
{
    // 基类实现...
};

// 派生类
class Derived : public Base<Derived>
{
    // 派生类实现...
};
// 关键点是派生类将自身作为模板参数传递给它的基类。这种看似"递归"的结构使基类能够在编译时访问派生类的成员。

// 工作原理
// CRTP的工作原理基于以下几点：
// 1.静态多态性：通过模板实例化而非虚函数实现多态
// 2.编译时解析：所有调用在编译时解析，没有运行时开销
// 3.基类访问派生类：基类可以通过static_cast转换为派生类类型

// 实际应用示例
// 1. 实现静态接口（无虚函数开销）
template <typename Derived>
class Shape
{
public:
    void draw()
    {
        // 调用派生类的实现
        static_cast<Derived *>(this)->drawImpl();
    }

    // 默认实现（可选）
    void drawImpl()
    {
        std::cout << "Drawing a generic shape" << std::endl;
    }

    double area()
    {
        return static_cast<Derived *>(this)->areaImpl();
    }

    // 派生类必须实现的方法
    double areaImpl()
    {
        throw std::runtime_error("Area calculation not implemented");
    }
};

class Circle : public Shape<Circle>
{
private:
    double radius;

public:
    Circle(double r) : radius(r) {}

    void drawImpl()
    {
        std::cout << "Drawing a circle with radius " << radius << std::endl;
    }

    double areaImpl()
    {
        return 3.14159 * radius * radius;
    }
};

class Rectangle : public Shape<Rectangle>
{
private:
    double width, height;

public:
    Rectangle(double w, double h) : width(w), height(h) {}

    void drawImpl()
    {
        std::cout << "Drawing a rectangle " << width << "x" << height << std::endl;
    }

    double areaImpl()
    {
        return width * height;
    }
};
int main()
{
    Circle c(5.0);
    Rectangle r(4.0, 6.0);

    c.draw(); // 调用 Circle::drawImpl()
    r.draw(); // 调用 Rectangle::drawImpl()

    std::cout << "Circle area: " << c.area() << std::endl;
    std::cout << "Rectangle area: " << r.area() << std::endl;

    // 以下是关键 - 可以创建不同类型的容器
    std::vector<Circle> circles;
    std::vector<Rectangle> rectangles;

    // 但不能创建 std::vector<Shape> - 因为没有共同的基类类型
}
// CRTP的优势
// 1.性能优化：避免虚函数调用的运行时开销
// 2.静态类型安全：编译时类型检查
// 3.代码复用：通过Mixin模式实现代码复用
// 4.接口强制实现：编译时检查接口实现
// 5.无需基类指针：避免了动态多态的限制

// CRTP的局限性
// 1.类型擦除问题：不能创建基类容器
// 2.代码膨胀：每个派生类会生成一个基类模板实例
// 3.编译时间增加：模板实例化会增加编译时间
// 4.调试复杂性：模板错误消息可能难以理解
// 5.设计复杂性：比传统继承更难理解和维护

// 实际应用场景
// CRTP在以下场景特别有用：
// 1.高性能计算：需要避免虚函数开销的场景
// 2.嵌入式系统：资源受限的环境
// 3.游戏引擎：需要高性能组件系统
// 4.数值计算库：如Eigen矩阵库
// 5.标准库实现：如STL迭代器

// CRTP vs 虚函数
// 虚函数方式
class ShapeVirtual
{
public:
    virtual void draw() = 0;
    virtual double area() = 0;
    virtual ~ShapeVirtual() {}
};

// CRTP方式
template <typename Derived>
class ShapeCRTP
{
public:
    void draw() { static_cast<Derived *>(this)->drawImpl(); }
    double area() { return static_cast<Derived *>(this)->areaImpl(); }
};
// 虚函数：运行时多态，有虚表开销，支持类型擦除
// CRTP：编译时多态，无运行时开销，不支持类型擦除
// CRTP 与虚函数的关键区别
// 1.编译时 vs 运行时
// CRTP：在编译时，编译器为每个派生类生成一个独立的基类模板实例。所有函数调用都在编译时被解析为具体类型的直接调用。
// 虚函数：在运行时，通过虚函数表和虚函数表指针进行动态分派。
// 2.内存布局
// CRTP 类：
// 没有虚函数表指针 (vptr)
// 内存布局与普通非多态类相同
// 对象大小不包含额外的虚函数表指针开销
// 3.使用虚函数的类：
// 每个对象都包含一个虚函数表指针 (通常是 4 或 8 字节)
// 这个指针指向一个虚函数表，表中存储着虚函数的地址

// 函数调用机制
// CRTP 函数调用：
template <typename Derived>
void Base<Derived>::method()
{
    static_cast<Derived *>(this)->derivedMethod();
}
// 编译器会将这个调用直接编译为对特定派生类方法的直接调用，没有间接寻址。

// 虚函数调用：
void Base::virtualMethod() { ... }